// Copyright (C) 2023 即时通讯网(52im.net) & Jack Jiang.
// The RainbowChat Project. All rights reserved.
// 
// 【本产品为著作权产品，合法授权后请放心使用，禁止外传！】
// 【本次授权给：<北京小羊驼科技有限公司>，授权编号：<NT231212144350>，代码指纹：<A.702363430.550>，技术对接人微信：<ID: wxid_wbyootvkdcgj22>】
// 【授权寄送：<收件：苏先生、地址：北京市大兴区北京密码西区6号楼1单元301、电话：18613885610、邮箱：bd@huiyuanxiang-inc.com>】
// 
// 【本系列产品在国家版权局的著作权登记信息如下】：
// 1）国家版权局登记名(简称)和权证号：RainbowChat    （证书号：软著登字第1220494号、登记号：2016SR041877）
// 2）国家版权局登记名(简称)和权证号：RainbowChat-Web（证书号：软著登字第3743440号、登记号：2019SR0322683）
// 3）国家版权局登记名(简称)和权证号：RainbowAV      （证书号：软著登字第2262004号、登记号：2017SR676720）
// 4）国家版权局登记名(简称)和权证号：MobileIMSDK-Web（证书号：软著登字第2262073号、登记号：2017SR676789）
// 5）国家版权局登记名(简称)和权证号：MobileIMSDK    （证书号：软著登字第1220581号、登记号：2016SR041964）
// * 著作权所有人：江顺/苏州网际时代信息科技有限公司
// 
// 【违法或违规使用投诉和举报方式】：
// 联系邮件：jack.jiang@52im.net
// 联系微信：hellojackjiang
// 联系QQ号：413980957
// 授权说明：http://www.52im.net/thread-1115-1-1.html
// 官方社区：http://www.52im.net
package com.x52im.rbchat.logic.chat_friend.utils;

import android.content.Context;
import android.util.Log;

import com.x52im.rbchat.IMClientManager;
import com.x52im.rbchat.MyApplication;
import com.x52im.rainbowchat.http.logic.dto.RosterElementEntity;
import com.x52im.rainbowchat.im.dto.ChatType;
import com.x52im.rainbowchat.im.dto.MsgBody4Friend;
import com.x52im.rainbowchat.im.dto.MsgBodyRoot;
import com.x52im.rainbowchat.im.dto.MsgType;
import com.x52im.rainbowchat.im.dto.RevokedMeta;
import com.x52im.rbchat.logic.chat_root.impl.MessageRevokingManager;
import com.x52im.rbchat.logic.chat_root.model.Message;
import com.x52im.rbchat.logic.chat_root.model.MessageExt;
import com.x52im.rbchat.utils.NotificationPromptHelper;
import com.x52im.rbchat.utils.PreferencesToolkits;
import com.x52im.rbchat.utils.PromtHelper;

/**
 * 一对一好友聊天的UI相关显示数据操作实用类..
 *
 * @author Jack Jiang(http://www.52im.net/space-uid-1.html)
 * @version 1.0
 */
public class ChatDataHelper {
    private final static String TAG = ChatDataHelper.class.getSimpleName();

    /**
     * 处理收到的聊天文本消息的数据模型处理和UI显示逻辑.
     *
     * @param context
     * @param ree
     * @param jsonStrOfTextMessage TextMessage对象的JSON文本
     * @param playPromtAudio
     * @param showNotification
     * @see #addChatMessageData_incoming(Context, String, RosterElementEntity, String, long, boolean, boolean, int)
     */
    public static void addChatMessageData_incoming(Context context
            , String fingerPrint
            , RosterElementEntity ree
            , String jsonStrOfTextMessage
            , long time
            , boolean playPromtAudio
            , boolean showNotification) {
        // 自v2.0后，普通的原始文本消息不是简单的纯文本了，而是TextMessage的JSON对象文件（此对象中的uid其实就是发送方的uid，目前主要用于服务端的离线消息存储时使用，客户端的话随便用）
        MsgBodyRoot tm = MsgBodyRoot.parseFromSender(jsonStrOfTextMessage);
        addChatMessageData_incoming(context, fingerPrint, ree, tm.getM(), time, playPromtAudio, showNotification, tm.getTy());
    }

    /**
     * 处理收到的聊天文本消息.
     *
     * @param context
     * @param fingerPrint      该条消息的指令码（也就是消息唯一ID）
     * @param ree
     * @param messageContent   真正的聊天文本内容（该内容可能是扁平文本（文本聊天消息）、文件
     *                         （语音留言、图片消息）），是{@link MsgBody4Friend}中的m内容
     * @param time
     * @param playPromtAudio
     * @param showNotification
     * @param msgType          真正的聊天消息类型（是TextMessage对象中的ty内容）
     */
    public static void addChatMessageData_incoming(Context context
            , String fingerPrint
            , RosterElementEntity ree
            , String messageContent
            , long time
            , boolean playPromtAudio
            , boolean showNotification
            , int msgType) {
        IMClientManager imc = MyApplication.getInstance2().getIMClientManager();

        // 如果收到的消息"撤回指令"，则需要单独特殊处理（因为"撤回"指令不是普通的聊天消息哦）
        if (msgType == MsgType.TYPE_REVOKE) {
            Log.i(TAG, "【这是消息撤回指令，马上处理撤回逻辑】 ==> msgType=" + msgType + "，fingerPrint = " + fingerPrint + "，messageContent=" + messageContent);

            // 开始处理撤回指令完整逻辑
            processRevokeMessage_incoming(ChatType.CHAT_TYPE_FREIDN$CHAT, fingerPrint, ree.getUser_uid(), messageContent);
            // 消息内容的显示（比如图片消息会显示"[图片]"这样的字串）
            String messageContentForShow = MessageExt.parseMessageContentPreview(context, messageContent, msgType);
            // 更新首页消息列表中的显示
            imc.getAlarmsProvider().addChatMessageAlarm(context, ree.getUser_uid(), ree.getNickNameWithRemark(), messageContentForShow, 0); // 未读数 TODO: 未来做到极致优化：如果该被撤回的消息处于未读数中则将未读数-1
            return;
        }

        //***************************************************************** 加入数据结构中
        Message cme = null;
        if (ree != null) {
            // 将一条消息放到该好友的消息列表中（放进去时会自动通知列表的观察者，而观察者将会实现ui的刷新）
            cme = MessageExt.prepareChatMessageData_incoming(ree.getUser_uid(), ree.getNickNameWithRemark(), messageContent, context, time, msgType);
            // 消息的指纹码（也就是唯一ID啦）
            cme.setFingerPrintOfProtocal(fingerPrint);
            // 将收到的消息数据放到聊天消息全局数据模型中
            imc.getMessagesProvider().putMessage(context, ree.getUser_uid(), cme);
        }

        //***************************************************************** 声音提示
        if (playPromtAudio && PreferencesToolkits.isChatMsgToneOpen(context, ree.getUser_uid()))
            // 来一个声音提示
            PromtHelper.messagePromt(context);

        //***************************************************************** 首页消息和系统Notification提示
        int flagNumToAdd = 0;
        // 消息内容的显示（比如图片消息会显示"[图片]"这样的字串）
        String messageContentForShow = MessageExt.parseMessageContentPreview(context, messageContent, msgType);
        // 当前聊天的界面处于后台时的消息提示 或者 不处于后台但当前聊天的并不是此用户时
        if (imc.getCurrentFrontChattingUserUID() == null || !imc.getCurrentFrontChattingUserUID().equals(ree.getUser_uid())) {

            // 未读消息数+1（当且仅当聊天界面处于后台时）
            flagNumToAdd += 1;
            // 系统Nitification通知
            if (showNotification && PreferencesToolkits.isChatMsgToneOpen(context, ree.getUser_uid())) {
                // 显示一个系统的Notification
                NotificationPromptHelper.showRecievedFriendMessageNotivication(context, ree.getUser_uid(), ree.getNickNameWithRemark(), messageContentForShow);
            }
        }
        // 无条件加一个提示到首页消息列表中（就像主流IM微信一样，可以很方便的找到最近聊天的人）
        imc.getAlarmsProvider().addChatMessageAlarm(context, ree.getUser_uid(), ree.getNickNameWithRemark(), messageContentForShow, flagNumToAdd);// 未读数+1哦
    }

    /**
     * 处理发出的聊天文本消息的数据模型处理和UI显示逻辑.
     *
     * @param context
     * @param friendUid
     * @param entity
     * @return
     */
    public static Message addChatMessageData_outgoing(Context context, String friendUid, Message entity) {
        // 将一条消息放到该好友的消息列表中（放进去时会自动通知列表的观察者，而观察者将会实现ui的刷新），不推荐像上面被注释地代
        // 码样直接操作消息列表数据集合，因为通过putMessage(..)方法可以通知观察者完成ui的刷新等工作，这样能提升编码的质量并统一该项业务的实现
        MyApplication.getInstance2().getIMClientManager().getMessagesProvider().putMessage(context, friendUid, entity);
        return entity;
    }

    /**
     * 处理收到的消息"撤回"指令逻辑。
     *
     * @param chatType       聊天类型，see {@link ChatType}
     * @param fpForRevokeCMD 撤回指令本身的指纹码
     * @param fromId         一对一聊天时此参数表示对方的uid，群聊时表示是群id
     * @param messageContent 消息撤回指令的内容
     */
    public static void processRevokeMessage_incoming(int chatType, String fpForRevokeCMD, String fromId, String messageContent) {
        IMClientManager imc = MyApplication.getInstance2().getIMClientManager();

        RevokedMeta messageContentObj = RevokedMeta.fromJSON(messageContent);
        if (messageContentObj != null && messageContentObj.getFpForMessage() != null) {

            //*** 更新本地sqlite数据库
            long row = MessageRevokingManager.updateSQLiteForMessage(chatType, messageContentObj.getFpForMessage(), messageContentObj);
            Log.i(TAG, "【消息撤回】被撤回消息时，updateSQLiteForMessage完成，影响row=" + row + "。(messageContentObj=" + messageContentObj + "，fpForRevokeCmd=" + fpForRevokeCMD + ")");

            Message originalMessage = null;
            //*** 更新消息列表数据对象内容
            if (chatType == ChatType.CHAT_TYPE_FREIDN$CHAT || chatType == ChatType.CHAT_TYPE_GUEST$CHAT) {
                originalMessage = imc.getMessagesProvider().findMessageByFingerPrint(fromId, messageContentObj.getFpForMessage());
            } else if (chatType == ChatType.CHAT_TYPE_GROUP$CHAT) {
                originalMessage = imc.getGroupsMessagesProvider().findMessageByParentFingerPrint(fromId, messageContentObj.getFpForMessage());
            } else {
                Log.w(TAG, "【消息撤回】未知的chatType=" + chatType + ", processRevokeMessage_incoming无法继续！");
                return;
            }

            if (originalMessage != null) {
                boolean sucess = MessageRevokingManager.updateModelForMessage(messageContentObj, originalMessage, fpForRevokeCMD, messageContentObj.getFpForMessage());
                if (sucess) {
                    Log.i(TAG, "【消息撤回】被撤回消息时，updateModelForMessage成功了。(messageContentObj=" + messageContentObj + "，fpForRevokeCmd=" + fpForRevokeCMD + ")");
                } else {
                    Log.w(TAG, "【消息撤回】被撤回消息时，updateModelForMessage失败了！(messageContentObj=" + messageContentObj + "，originalMessage=" + originalMessage + "，fpForRevokeCmd=" + fpForRevokeCMD + ")");
                }
            } else {
                Log.w(TAG, "【消息撤回】被撤回消息时，正准备updateModelForMessage，但数据为空，originalMessage=null");
            }
        } else {
            Log.w(TAG, "【消息撤回】被撤回消息时，正准备updateSQLiteForMessage等，但数据为空，messageContentObj=" + messageContentObj);
        }
    }
}
